package com.uvnos4j.matilda.system.service.impl;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.uvnos4j.matilda.commons.dto.QueryParam;
import com.uvnos4j.matilda.commons.exception.ServiceException;
import com.uvnos4j.matilda.system.domain.SysAcl;
import com.uvnos4j.matilda.system.domain.SysRoleAcl;
import com.uvnos4j.matilda.system.error.SystemError;
import com.uvnos4j.matilda.system.mapper.SysAclMapper;
import com.uvnos4j.matilda.system.mapper.SysRoleAclMapper;
import com.uvnos4j.matilda.system.service.SysAclService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * 权限 Service 实现
 * <p>
 * Description:权限 Service 实现
 * </p>
 *
 * @author Guo.wl
 * @version v1.0.0
 * @see com.uvnos4j.matilda.system.service.impl
 * @since 2020-08-31 23:11:53
 */
@Service
@Transactional(readOnly = true)
public class SysAclServiceImpl extends ServiceImpl<SysAclMapper, SysAcl> implements SysAclService {

    @Autowired
    private SysRoleAclMapper sysRoleAclMapper;

    /**
     * 查询权限
     *
     * @param param param
     * @return 权限列表
     */
    @Override
    public List<SysAcl> list(QueryParam param) {
        LambdaQueryWrapper<SysAcl> lqw = new LambdaQueryWrapper<>();
        lqw.orderByAsc(SysAcl::getSeq);
        return baseMapper.selectList(lqw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(SysAcl sysAcl) {
        if (countSameAtParent(sysAcl.getParentId(), sysAcl.getName(), null)) {
            throw new ServiceException(SystemError.ACL_REPEAT_AT_SAME_PARENT);
        }
        sysAcl.setCreateTime(DateTime.now());
        return baseMapper.insert(sysAcl) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(SysAcl sysAcl) {
        if (Objects.equals(sysAcl.getId(), sysAcl.getParentId())) {
            throw new ServiceException(SystemError.ACL_SAME_AS_PARENT);
        }
        if (countSameAtParent(sysAcl.getParentId(), sysAcl.getName(), sysAcl.getId())) {
            throw new ServiceException(SystemError.ACL_REPEAT_AT_SAME_PARENT);
        }
        return baseMapper.updateById(sysAcl) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        // 校验
        for (Serializable id : idList) {
            SysAcl acl = baseMapper.selectById(id);
            if (acl == null) {
                SystemError.ACL_NO_EXIST.setMessage(id);
                throw new ServiceException(SystemError.ACL_NO_EXIST);
            }

            LambdaQueryWrapper<SysAcl> lqw = new LambdaQueryWrapper<>();
            lqw.eq(SysAcl::getParentId, id);
            int count = baseMapper.selectCount(lqw);
            if (count > 0) {
                SystemError.ACL_HAS_CHILDREN.setMessage(acl.getName());
                throw new ServiceException(SystemError.ACL_HAS_CHILDREN);
            }
        }
        // 删除角色权限关系
        LambdaQueryWrapper<SysRoleAcl> lqw = new LambdaQueryWrapper<>();
        lqw.in(SysRoleAcl::getAclId, idList);
        sysRoleAclMapper.delete(lqw);

        // 删除权限
        int affectedRows = baseMapper.deleteBatchIds(idList);
        return affectedRows > 0;
    }

    @Override
    public List<SysAcl> findByUserId(Long userId) {
        return baseMapper.findByUserId(userId);
    }

    @Override
    public List<SysAcl> findByRoleId(Long roleId) {
        return baseMapper.findByRoleId(roleId);
    }

    /**
     * 新增或修改时相同父权限是否含有含有同名权限
     *
     * @param parentId 父权限Id
     * @param name     权限名称
     * @param id       权限Id，修改时用于排除自身
     * @return true含有同名权限；false不含同名权限
     */
    private boolean countSameAtParent(Long parentId, String name, Long id) {
        LambdaQueryWrapper<SysAcl> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysAcl::getParentId, parentId).eq(SysAcl::getName, name).ne(id != null, SysAcl::getId, id);
        int count = baseMapper.selectCount(lqw);
        return count > 0;
    }


}
